﻿// ****************************************************************
// Copyright 2012, Stephan Burguchev
// e-mail: me@sburg.net
// ****************************************************************
// *
using System;
using System.IO;
using Moq;
using NUnit.Framework;
using Updater.Common;
using Updater.Sources;
using Updater.Updates;

namespace Updater.Tests
{
    [TestFixture]
    public class ZipArchiveUpdateTests
    {
        private TestDataProvider _dataProvider;
        private TempDirectory _tempDirectory;

        [Test]
        public void Download_RealDownload()
        {
            var zipArchiveUri = new Uri(this._dataProvider.ZipArchivePath);
            ZipArchiveUpdate update = this.createUpdate();
            var mock = new Mock<ISource>(MockBehavior.Strict);
            mock.Setup(s => s.Download(zipArchiveUri, It.IsAny<Stream>(), It.IsAny<Action<DownloadProgressInfo>>()))
                .Callback(
                    delegate(Uri loc, Stream d, Action<DownloadProgressInfo> info)
                    {
                        using (FileStream s = File.OpenRead(this._dataProvider.ZipArchivePath))
                        {
                            s.CopyTo(d);
                        }
                    });
            update.Source = mock.Object;

            update.Download(this.downloadInfoCallback);

            mock.Verify(
                s => s.Download(zipArchiveUri, It.IsAny<Stream>(), It.IsAny<Action<DownloadProgressInfo>>()),
                Times.Once());
        }

        [Test]
        public void Download_RedownloadBecauseOfInvalidChecksum()
        {
            var zipArchiveUri = new Uri(this._dataProvider.ZipArchivePath);
            ZipArchiveUpdate update = this.createUpdate();
            update.Information.Checksum[0] = 0;
            File.Copy(
                this._dataProvider.ZipArchivePath,
                Path.Combine(
                    this._dataProvider.UpdaterCacheDirectory, string.Format("update-{0}.zip", update.Information.Version)));
            var mock = new Mock<ISource>(MockBehavior.Strict);
            mock.Setup(s => s.Download(zipArchiveUri, It.IsAny<Stream>(), It.IsAny<Action<DownloadProgressInfo>>()));
            update.Source = mock.Object;

            update.Download(this.downloadInfoCallback);

            mock.Verify(
                s => s.Download(zipArchiveUri, It.IsAny<Stream>(), It.IsAny<Action<DownloadProgressInfo>>()),
                Times.Once());
        }

        [Test]
        public void Download_SkippingDownload()
        {
            var zipArchiveUri = new Uri(this._dataProvider.ZipArchivePath);
            ZipArchiveUpdate update = this.createUpdate();
            File.Copy(
                this._dataProvider.ZipArchivePath,
                Path.Combine(
                    this._dataProvider.UpdaterCacheDirectory, string.Format("update-{0}.zip", update.Information.Version)));
            var mock = new Mock<ISource>(MockBehavior.Strict);
            mock.Setup(s => s.Download(zipArchiveUri, It.IsAny<Stream>(), It.IsAny<Action<DownloadProgressInfo>>()));
            update.Source = mock.Object;

            update.Download(this.downloadInfoCallback);

            mock.Verify(
                s => s.Download(zipArchiveUri, It.IsAny<Stream>(), It.IsAny<Action<DownloadProgressInfo>>()),
                Times.Never());
        }

        [SetUp]
        public void SetUp()
        {
            this._tempDirectory = new TempDirectory();
            this._dataProvider = new TestDataProvider(this._tempDirectory);
        }

        [TearDown]
        public void TearDown()
        {
            this._tempDirectory.Dispose();
        }

        private ZipArchiveUpdate createUpdate()
        {
            return new ZipArchiveUpdate
                {
                    Configuration = this._dataProvider.CreateConfiguration(),
                    Information = this._dataProvider.CreateUpdateInformation1()
                };
        }

        private void downloadInfoCallback(DownloadProgressInfo info)
        {
            Assert.LessOrEqual(info.DownloadedInBytes, info.FullSizeInBytes);
            Assert.GreaterOrEqual(info.DownloadedInBytes, 0);
        }
    }
}
